package com.hdu.service.impl;

import com.alibaba.fastjson.JSON;
import com.hdu.dto.ChatRecordDTO;
import com.hdu.dto.RecallMessageDTO;
import com.hdu.dto.WebsocketMessageDTO;
import com.hdu.entity.Chat;
import com.hdu.enums.ChatTypeEnum;
import com.hdu.mapper.ChatMapper;
import com.hdu.util.BeanCopyUtils;
import com.hdu.util.HTMLUtils;
import com.hdu.util.IpUtils;
import com.hdu.vo.VoiceVO;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * websocket服务
 */
@Data
@Service
@ServerEndpoint(value = "/websocket/{param}", configurator = WebSocketServiceImpl.ChatConfigurator.class)
public class WebSocketServiceImpl {

    /**
     * 用户session
     */
    private Session session;

    /**
     * 用户param
     */
    private String param;

    /**
     * 用户session集合
     */
    private static CopyOnWriteArraySet<WebSocketServiceImpl> webSocketSet = new CopyOnWriteArraySet<>();

    @Autowired
    public void setChatRecordMapper(ChatMapper chatMapper) {
        WebSocketServiceImpl.chatMapper = chatMapper;
    }


    private static ChatMapper chatMapper;


    /**
     * 获取客户端真实ip
     */
    public static class ChatConfigurator extends ServerEndpointConfig.Configurator {

        public static String HEADER_NAME = "X-Real-IP";

        @Override
        public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
            try {
                String firstFoundHeader = request.getHeaders().get(HEADER_NAME.toLowerCase()).get(0);
                sec.getUserProperties().put(HEADER_NAME, firstFoundHeader);
            } catch (Exception e) {
                sec.getUserProperties().put(HEADER_NAME, "未知ip");
            }
        }
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("param") String param) throws IOException {
        System.out.println("加入连接");
        // 加入连接
        this.session = session;
        this.param = param;
        webSocketSet.add(this);

        // 更新在线人数
        updateOnlineCount();
        // 加载历史聊天记录
        ChatRecordDTO chatRecordDTO = listChatRecords(new Chat());
        // 发送消息
        WebsocketMessageDTO messageDTO = WebsocketMessageDTO.builder()
                .type(ChatTypeEnum.HISTORY_RECORD.getType())
                .data(chatRecordDTO)
                .build();
        synchronized (session) {
            session.getBasicRemote().sendText(JSON.toJSONString(messageDTO));
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        WebsocketMessageDTO messageDTO = JSON.parseObject(message, WebsocketMessageDTO.class);
        switch (Objects.requireNonNull(ChatTypeEnum.getChatType(messageDTO.getType()))) {
            case SEND_MESSAGE:
                // 发送消息
                Chat chat = JSON.parseObject(JSON.toJSONString(messageDTO.getData()), Chat.class);
                // 过滤html标签
                chat.setContent(HTMLUtils.deleteTag(chat.getContent()));
                chat.setCreateTime(LocalDateTime.now());
                chatMapper.insert(chat);
                messageDTO.setData(chat);
                // 广播消息
                broadcastMessage(messageDTO);
                break;
            case RECALL_MESSAGE:
                // 撤回消息
                RecallMessageDTO recallMessage = JSON.parseObject(JSON.toJSONString(messageDTO.getData()), RecallMessageDTO.class);
                // 删除记录
                chatMapper.deleteById(String.valueOf(recallMessage.getId()));
                // 广播消息
                broadcastMessage(messageDTO);
                break;
            case HISTORY_RECORD:
                // 加载历史聊天记录
                ChatRecordDTO chatRecordDTO = listChatRecords(JSON.parseObject(JSON.toJSONString(messageDTO.getData()), Chat.class));
                // 发送消息
                messageDTO.setType(ChatTypeEnum.HISTORY_RECORD.getType());
                messageDTO.setData(chatRecordDTO);
                synchronized (session) {
                    session.getBasicRemote().sendText(JSON.toJSONString(messageDTO));
                }
                break;
            case HEART_BEAT:
                // 心跳消息
                messageDTO.setData("pong");
                session.getBasicRemote().sendText(JSON.toJSONString(JSON.toJSONString(messageDTO)));
            default:
                break;
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() throws IOException {
        // 更新在线人数
        webSocketSet.remove(this);
        updateOnlineCount();
    }

    /**
     * 加载历史聊天记录
     *
     * @return 加载历史聊天记录
     */
    private ChatRecordDTO listChatRecords(Chat chat) {

//        //1. 设置分页参数
//        PageHelper.startPage(1, 5);
        // 获取聊天历史记录
        List<Chat> chatRecordList = chatMapper.selectChat(chat);

//        Page<Chat> p = (Page<Chat>) chatRecordList;
//
//        //3. 封装PageBean对象
//        PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
//        List<Chat> chatList = pageBean.getRows();
//        Collections.reverse(chatList);
        // 获取当前用户ip
//        String ipAddress = endpointConfig.getUserProperties().get(ChatConfigurator.HEADER_NAME).toString();
        return ChatRecordDTO.builder()
                .chatRecordList(chatRecordList)
                .ipAddress("")
                .ipSource(IpUtils.getIpSource(""))
                .build();
    }

    /**
     * 更新在线人数
     *
     * @throws IOException io异常
     */
    @Async
    public void updateOnlineCount() throws IOException {
        List<String> paramList = new ArrayList<>();
        for (WebSocketServiceImpl webSocketService : webSocketSet) {
            paramList.add(webSocketService.param);
        }
        // 获取当前在线人数
        WebsocketMessageDTO messageDTO = WebsocketMessageDTO.builder()
                .type(ChatTypeEnum.ONLINE_COUNT.getType())
                .data(paramList)
                .build();
        // 广播消息
        broadcastMessage(messageDTO);
    }

    /**
     * 发送语音
     *
     * @param voiceVO 语音路径
     */
    public void sendVoice(VoiceVO voiceVO) {
        // 保存记录
        Chat chat = BeanCopyUtils.copyObject(voiceVO, Chat.class);
        chatMapper.insert(chat);
        // 发送消息
        WebsocketMessageDTO messageDTO = WebsocketMessageDTO.builder()
                .type(ChatTypeEnum.VOICE_MESSAGE.getType())
                .data(chat)
                .build();
        // 广播消息
        try {
            broadcastMessage(messageDTO);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 广播消息
     *
     * @param messageDTO 消息dto
     * @throws IOException io异常
     */
    private void broadcastMessage(WebsocketMessageDTO messageDTO) throws IOException {
        for (WebSocketServiceImpl webSocketService : webSocketSet) {
            synchronized (webSocketService.session) {
                webSocketService.session.getBasicRemote().sendText(JSON.toJSONString(messageDTO));
            }
        }
    }

}
